home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Cool Demos, SDKs, & Tools / Demos⁄Tools⁄Offers / Alpha ƒ / Tcl / Packages / elecExpansions.tcl < prev    next >
Text File  |  1999-04-07  |  24KB  |  840 lines

  1. # Note from Vince: bug reports for this file should go to Tom Fetherston (install)
  2. # (and probably to me too, since I have made some changes)
  3.  
  4. ##===========================================================================
  5. # elecExpansions, formerly acronymExpansions, formerly 'Word-Combinations Completion'
  6.  
  7. # AUTHOR
  8. #    
  9. #    Thomas R. Fetherston
  10. #    Internet: ranch1@earthlink.net
  11. #    USnail:   94 Lipp Ave, Pittsburgh, PA 15229-2001
  12. #
  13. ################################################################################
  14. # HISTORY
  15. #                  
  16. # modified                 who rev reason
  17. # ----------------------   --- --- ------
  18. # 12/2/97                   trf 1.8 made changes to fix TeX expansions
  19. # 05/22/1997               trf 1.7 Removed uses of 'oneSpace', this messed up stop
  20. #                                    locations. 
  21. # 05/14/1997               VD  1.6 Changed proc names to reflect new naming scheme
  22. # 12/30/1996               trf 1.5 Modified so that this could be integrated with 
  23. #                                   Vince Darley's Completion package.
  24. # 07/14/1996 {01:21:20 PM} trf 1.4 Changed previous hit to a list of previous hits
  25. #                                   so hits would be offered only once.
  26. # 07/14/1996 {12:04:37 PM} trf 1.3 work around for regexp to include a close bracket
  27. # 07/12/1996 {12:53:38 AM} trf 1.2 Allow hint to be suffixed with certain puncuation
  28. #                                    marks and still be expanded. Added hint check.
  29. # 07/11/1996 {10:29:51 PM} trf 1.1 Allow expansion of hint prefixed with non-
  30. #                                   alphabetic character(s).
  31. #                                    Ensure Hit used is followed with only one
  32. #                                    space.
  33. # 07/05/1996 {10:28:20 PM} trf 1.0 Original
  34. ################################################################################
  35.  
  36. # Based on wordCompetion.tcl
  37. # Originally composed by Mark Nagata (nagata@kurims.kyoto-u.ac.jp) 
  38. # for Alpha 5.76, 4/22/94.
  39. # Modified by Tim van der Leeuw (tnleeuw@cs.vu.nl), 9/14/94.
  40. # Modified by Tom Fetherston
  41. # All the global variables needed to store state information between calls
  42. # (start with __Gcw_)
  43. #
  44. # This provides a different kind of word completion than the
  45. # distribution provides, (wordCompletion.tcl).  When you find yourself
  46. # typing a lot of variable and function names over and over, and these
  47. # names are word-combinations where the name is formed by either
  48. # capitalizing each word or separating them with an underscore, just
  49. # type the initial letter of each word and invoke acronymExpansion
  50. # instead.
  51.  
  52. # The idea of this modification is to allow you to type a string
  53. # consisting of the initial letters of the words that have been joined
  54. # to make up a variable, function, or procedure name.  This is often
  55. # shorter and more natural than typing a few letter and using
  56. # wordCompletion.  As I developed this routine I found that a regexp
  57. # for more than three letters caused search to choke so only those
  58. # letters of a "hint" are significant.  A three letter pattern is used
  59. # for the search.  After a possible hit is located, it is turned into
  60. # an acronym and checked against the "hint"
  61. ##
  62. # to do list
  63. # ----------
  64. # change __Gcw_prevHint to a list of previous hits so we only get new hits
  65.  
  66. # monitor the character(s) to the right of the cursor point so the
  67. # automatic, "oneSapce" can be suppressed, e.g. if a comma, close
  68. # "bracket", or return immediately follows, let the inserted text abut
  69. # it without a space
  70. # cause a hint that ends in an '[' to search for a hit that is a
  71. # parameterized routine.  (what is a routine depends on the mode), and
  72. # invoke a "replacement that includes a template for the proper number
  73. # of arguments
  74.  
  75. # let numerals play a role in finding a "Hit"
  76.  
  77. # let an invocation include a file or list to be searched instead of
  78. # the current window.
  79. ##
  80. # The string you are going to use expansion on is entered in
  81. # lowercase.  The words in the target you are trying to hit have to
  82. # start with a capital (except the first word), or, be separated by an
  83. # underscore.
  84.  
  85. # The hint can be embedded between non-alphabetic characters and
  86. # certain punctuation marks ( '[', '(', '{', ',', ';', ':', ''', '"',
  87. # ']', ')', '}' ).  The expanded hint remains so embedded, and the
  88. # cursor appears one space beyond the trailing punctuation.
  89.  
  90. # e.g. if sin($gl) was expanded, we would get sin($__Gcw_len) (in this
  91. # file).  similarly, mouse($gph, would expand to
  92. # 'mouse($__Gcw_prevHint, ', done twice, we would get
  93. # 'mouse($__Gcw_prevHit, '.
  94. ##
  95. # The following binding is just a suggestion.  It is the one that I
  96. # like best, I have this in my pref.tcl file
  97. # ascii 0x20 <c> bind::Expansion
  98. # i.e. command-<space>
  99.  
  100. #================================================================================
  101.  
  102. alpha::extension elecExpansions 9.0b3 {
  103.     alpha::package require elecBindings 9.0b1
  104.     lunion flagPrefs(Electrics) listPickIfMultExpds
  105.     # similarly for expansions
  106.     newPref flag listPickIfMultExpds 0
  107. } maintainer {
  108.     "Tom Fetherston" "" ""
  109. } uninstall this-file help {file "ElecCompletions Help"}
  110.  
  111. set __Gcw_prevHintPos -1
  112. set __Gcw_prevHint {}
  113. set __Gcw_prevsrcListName {}
  114.  
  115. ensureset __Gcw_already_expanding error
  116. ensureset __Gcw_pos_expanding -1 
  117.  
  118. ## 
  119.  # -------------------------------------------------------------------------
  120.  #     
  121.  #    "bind::Expansion"    --
  122.  #    
  123.  #  If we're already completing, jump to that procedure, else go
  124.  #  through a mode-dependent list of expansion procedures given by the
  125.  #  array 'completions', these return either '1' to indicate
  126.  #  termination, or '0' to say either that they failed or that they
  127.  #  succeeded and that further expansion procedures may be applied. 
  128.  # -------------------------------------------------------------------------
  129.  ##
  130. proc bind::Expansion {} {
  131.     if {![completion::tabDeleteSelection]} return
  132.     
  133.     global __Gcw_already_expanding
  134.     if {[elec::notAlreadyExpanding]} {
  135.     set __Gcw_already_expanding error
  136.     if {[expansion::user]} return
  137.     set m [modeALike]
  138.     global expanders
  139.     set curPos [getPos]
  140.     if {![catch {set expandersList $expanders($m)}]} {
  141.         foreach e $expandersList {
  142.         if {[completion $m $e]} return
  143.         }
  144.     }
  145.     #if none of the expanders succeeded, (or, don't exist) try
  146.     if {[pos::compare [getPos] == $curPos]} {
  147.         expansion::acronym
  148.     }
  149.     }
  150. }
  151.  
  152. ## 
  153.  # -------------------------------------------------------------------------
  154.  #     
  155.  #    "elec::notAlreadyExpanding" --
  156.  #    
  157.  #  Call this to check if we should divert directly to a previously
  158.  #  registered expansion procedure instead of starting from scratch. 
  159.  # -------------------------------------------------------------------------
  160.  ##
  161. proc elec::notAlreadyExpanding {} {
  162.     global __Gcw_already_expanding __Gcw_pos_expanding
  163.     # do the old expansion if possible
  164.     if {[pos::compare $__Gcw_pos_expanding == [getPos]]} {
  165.     return [catch {elec::completion [modeALike] $__Gcw_already_expanding}]
  166.     } else {
  167.     return 1
  168.     }    
  169. }
  170.  
  171. ## 
  172.  # -------------------------------------------------------------------------
  173.  #     
  174.  #    "elec::alreadyExpanding"    --
  175.  #    
  176.  #  If a expansion routine has been called once, and would like to be
  177.  #  called again (to cycle through a number of possibilities), then it
  178.  #  should register itself with this procedure. 
  179.  # -------------------------------------------------------------------------
  180.  ##
  181. proc elec::alreadyExpanding { proc } {
  182.     global __Gcw_already_expanding __Gcw_pos_expanding
  183.     # store the given expansion
  184.     set __Gcw_already_expanding $proc
  185.     set __Gcw_pos_expanding [getPos]
  186. }
  187.  
  188.  
  189. ## 
  190.  # These declare, in order, the names of the expander procedures for
  191.  # each mode.  The actual procedure must be named
  192.  # '${mode}Expansion::${listItem}', unless the item is 'expansions::*'
  193.  # in which case that actual procedure is called.
  194.  ##
  195. #===========================================================================
  196.  
  197. set expanders(TeX) {ExCmd}
  198. set expanders(Tcl) {}
  199. set expanders(C) {}
  200.  
  201. # just so we have one!
  202. set userExpansionw(date) {◊kill0◊[lindex [mtime [now]] 0]}
  203.  
  204. namespace eval expansion {}
  205.  
  206. proc expansion::user { {cmd ""} } {
  207.     if {![string length $cmd]} { set cmd [completion::lastWord] }
  208.     if {[containsSpace $cmd]} { return 0 }
  209.     
  210.     set curPos [getPos]
  211.     
  212.     elec::findCmd $cmd userExpansionw
  213.     #if the above call resulted in a detectable action, (i.e. the
  214.     # current positon has change), return 1
  215.     if {[pos::compare [getPos] == $curPos]} {
  216.     return 0
  217.     } else {
  218.     return 1
  219.     }
  220. }
  221.  
  222. #    -------------------
  223. proc expansion::acronym {} {
  224.     
  225.     global __Gcw_len
  226.     global __Gcw_prevHintPos
  227.     global __Gcw_prevHint
  228.     global __Gcw_endPrevRpl
  229.     global __Gcw_prevHits
  230.     global __Gcw_patt
  231.     global __Gcw_nextStart
  232.     global __Gcw_above_BELOW
  233.     
  234.     set To [getPos]
  235.     set lastChar [lookAt [pos::math $To - 1]]
  236.     set hintCapper [lookAt $To]
  237.     switch -- $hintCapper {
  238.     "\)" -
  239.     "\}" -
  240.     "\]" - 
  241.     " "  -
  242.     "\t" {
  243.         if {$lastChar != ","} {
  244.         set trailingWhite {} 
  245.         } else {
  246.         set trailingWhite " "
  247.         }     
  248.     }
  249.     "default" {
  250.         switch -- $lastChar {
  251.         "\(" -
  252.         "\{" -
  253.         "\{" - 
  254.         " "  -
  255.         "\t" {
  256.             set trailingWhite {} 
  257.         }
  258.         default {
  259.             set trailingWhite " "
  260.         }
  261.         }
  262.         
  263.     }
  264.     }
  265.     
  266.     backwardWord
  267.     set From [getPos]
  268.     
  269.     # adjust From to prune any non alphabetic prefix
  270.     set hint [getText $From $To]
  271.     
  272.     # The following variables may not come into existence in the regexp
  273.     #  below, so set up defaults.
  274.     set tail ""
  275.     set punc ""
  276.     #can not seem to include a close brack as below
  277.     #regexp {([a-zA-Z_]+)([\(\{\[,;:'"\}\)\]])*[     ]*$} $hint tail hint punc
  278.     
  279.     #work around on above
  280.     regexp {([a-zA-Z0-9_]+)(([\(\{\[,;:'"\}\)])*(\])*([\(\{\[,;:'"\}\)])*)[     ]*$} $hint tail hint punc
  281.     set From [pos::math $To - [string length $tail]]
  282.     
  283.     #   this is a 1stTry, but hint is illegal
  284.     if {[pos::compare $From != $__Gcw_prevHintPos]} {
  285.     if {[regexp {[0-9_]} $hint] > 0} {
  286.         alertnote "Ilegal hint, must have only letters in it."
  287.         select $From $To
  288.         set __Gcw_prevHintPos -1
  289.         return
  290.     } elseif {$From==$To} {
  291.         alertnote "Was not able to find any hint."
  292.         set __Gcw_prevHintPos -1
  293.         return
  294.     }
  295.     }
  296.     
  297.     
  298.     # adjust To, leaving trailing spaces or tabs
  299.     set To [expr $From + [string length [append junk $hint $punc]]]
  300.     
  301.     # if (Trying to complete a new hint)
  302.     if {[pos::compare $From != $__Gcw_prevHintPos]} {
  303.     set __Gcw_prevHint $hint
  304.     set __Gcw_prevHits {}
  305.     set __Gcw_len [string length $hint]
  306.     set __Gcw_patt  [pFI $hint]
  307.     set __Gcw_above_BELOW 0
  308.     
  309.     set start [pos::math $From - 1]    
  310.     set beg {}; set end {}
  311.     set foundAbove 0
  312.     elec::_searchAboveForHit start   beg end Hit foundAbove
  313.     
  314.     if {$foundAbove} {
  315.         lappend __Gcw_prevHits $Hit
  316.         
  317.         # put in the Hit, 
  318.         set replacement {}
  319.         append replacement $Hit $punc $trailingWhite 
  320.         replaceText $From $To $replacement
  321.         goto [pos::math $From + [string length $replacement]]
  322.         #         oneSpace
  323.         
  324.         
  325.         message "found above."
  326.         set __Gcw_prevHintPos $From
  327.         
  328.         set __Gcw_endPrevRpl [getPos]
  329.         elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  330.         return
  331.     }
  332.     
  333.     set start $To    
  334.     set beg {}; set end {}
  335.     set __Gcw_above_BELOW 1
  336.     set foundBelow 0
  337.     elec::_searchBelowForHit start   beg end Hit foundBelow
  338.     
  339.     if {$foundBelow} {
  340.         lappend __Gcw_prevHits $Hit
  341.         
  342.         # put in the Hit, 
  343.         set replacement {}
  344.         append replacement $Hit $punc $trailingWhite 
  345.         replaceText $From $To $replacement
  346.         goto [pos::math $From + [string length $replacement]]
  347.         
  348.         message "found below."
  349.         set __Gcw_prevHintPos $From
  350.         
  351.         set __Gcw_endPrevRpl [getPos]
  352.         elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  353.         return
  354.     }
  355.     
  356.     #No Hit for this hint exists
  357.     #     goto $To
  358.     #     backwardWordSelect
  359.     select $From $To
  360.     set __Gcw_prevHintPos -1
  361.     return
  362.     
  363.     # else: we are re-trying the previous hint
  364.     } else {  
  365.     while 1 {
  366.         #pre-set fndMsg, in case there is a valid Hit for this iteration
  367.         if {$__Gcw_above_BELOW} {
  368.         set fndMsg "found below."
  369.         } else {
  370.         set fndMsg "found above."
  371.         }
  372.         
  373.         set start $__Gcw_nextStart    
  374.         set beg {}; set end {}
  375.         set foundByContinuedSearch 0
  376.         elec::_continueSearchForHit start  beg end Hit foundByContinuedSearch
  377.         
  378.         if {$foundByContinuedSearch} {            
  379.         #if (this Hit is not the same as the last one)
  380.         if {[lsearch -exact $__Gcw_prevHits $Hit] == -1} {
  381.             
  382.             #add the hit to the list of previous hits
  383.             lappend $__Gcw_prevHits $Hit
  384.             
  385.             # put in the Hit, 
  386.             if {($punc == ",") && [info exists tail]} {
  387.             set trailingWhite " " 
  388.             } 
  389.             # put in the Hit, 
  390.             set replacement {}
  391.             append replacement $Hit $punc $trailingWhite 
  392.             replaceText $From $To $replacement
  393.             goto [pos::math $From + [string length $replacement]]
  394.             
  395.             message $fndMsg
  396.             set __Gcw_endPrevRpl [getPos]
  397.             elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  398.             return
  399.             
  400.             #else: this Hit does not differ from the last
  401.         } else {
  402.             elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  403.         }
  404.         
  405.         #else: another Hit was not found    
  406.         } else {
  407.         #if (no more Hits can exist, because we have searched all the text)
  408.         if {$__Gcw_above_BELOW} {
  409.             message "Not found."
  410.             #                 goto $To
  411.             #                 backwardWordSelect
  412.             select $__Gcw_prevHintPos $__Gcw_endPrevRpl
  413.             set __Gcw_prevHintPos -1
  414.             return
  415.             #else: we haven't tried BELOW
  416.         } else {
  417.             set __Gcw_above_BELOW 1
  418.             set __Gcw_nextStart $__Gcw_endPrevRpl
  419.         }
  420.         }
  421.         
  422.     }
  423.     }
  424. }
  425.  
  426. #    ---
  427. proc pFI wordStarters {
  428.     proc firstPost {char} {
  429.     return [format "(%s|%s)" [string toupper $char] $char ]
  430.     }
  431.     
  432.     proc fencePost {char} {
  433.     return [format {(%1$s|_%1$s|_%2$s)} [string toupper $char] $char ]
  434.     }
  435.     
  436.     set identifierLeader {(_|__)?}
  437.     set wordTail {[a-z0-9]*}
  438.     set identifierTail {[a-zA-Z0-9_]*}
  439.     
  440.     set idx_Last [expr {[string length $wordStarters]-1}]
  441.     if {$idx_Last>2} {set idx_Last 2}
  442.     
  443.     set searchPatt  $identifierLeader
  444.     append searchPatt [firstPost [string index $wordStarters 0]] 
  445.     append searchPatt $wordTail
  446.     
  447.     for {set i 1} {$i < $idx_Last} {incr i} {
  448.     append searchPatt [fencePost [string index $wordStarters $i]]
  449.     append searchPatt $wordTail
  450.     }
  451.     append searchPatt [fencePost [string index $wordStarters $i]]
  452.     append searchPatt $identifierTail
  453.     return $searchPatt
  454. }
  455.  
  456. #Note: in all the following scripts that start with uplevel…, the
  457. # agrguments are "fake", and serve only to show what variables
  458. # are used by these macro-like subroutines.  Their primary purpose
  459. # is to make the above code more readable.  Each is started with
  460. # an underscore to indicate that they are internal to another
  461. # routine, and should not be called by themselves.
  462.  
  463. #    ------------------  -in--  -out--------(bool)-
  464. proc elec::_searchAboveForHit {start  beg end Hit success} {
  465.     
  466.     uplevel {
  467.     set BegEnd {-1 -1}
  468.     set moreToSearch 1
  469.     while {$moreToSearch} {
  470.         set foundAbove [expr {![catch {search -s -f 0 -r 1 -i 0 -m 1 -- $__Gcw_patt $start} BegEnd]}]
  471.         if {!$foundAbove} {unset BegEnd ; break}
  472.         set beg [lindex $BegEnd 0]
  473.         set end [lindex $BegEnd 1]
  474.         unset BegEnd
  475.         set Hit [getText $beg $end]
  476.         
  477.         set fullMatch [elec::acronymsAreEqual $hint $Hit]
  478.         if {$fullMatch} {
  479.         break
  480.         
  481.         } else {
  482.         set foundAbove 0
  483.         }
  484.         
  485.         if {[pos::compare $beg <= [minPos]]} {
  486.         set moreToSearch 0
  487.         } else {
  488.         set start [pos::math $beg-1]
  489.         }
  490.     }
  491.     }
  492. }
  493.  
  494. #    ------------------  -in--  -out--------(bool)-
  495. proc elec::_searchBelowForHit {start  beg end Hit success} {
  496.     
  497.     uplevel {
  498.     set BegEnd {-1 -1}
  499.     set moreToSearch 1
  500.     while {$moreToSearch} {
  501.         set foundBelow [expr {![catch {search -s -f 1 -r 1 -i 0 -m 1 -- \
  502.           $__Gcw_patt $start} BegEnd]}]
  503.         if {!$foundBelow} {unset BegEnd ; break}
  504.         set beg [lindex $BegEnd 0]
  505.         set end [lindex $BegEnd 1]
  506.         set Hit [getText $beg $end]
  507.         unset BegEnd
  508.         
  509.         set fullMatch [elec::acronymsAreEqual $hint $Hit]
  510.         if {$fullMatch} {
  511.         break
  512.         
  513.         } else {
  514.         set foundBelow 0
  515.         }
  516.         
  517.         if {[pos::compare $end >= [maxPos]]} {
  518.         set moreToSearch 0
  519.         } else {
  520.         set start [expr $end]
  521.         }
  522.     }
  523.     }
  524. }
  525.  
  526. #    ---------------------  -in--  -out--------(bool)-
  527. proc elec::_continueSearchForHit {start  beg end Hit success} {
  528.     
  529.     uplevel {
  530.     set BegEnd {-1 -1}
  531.     set moreToSearch 1
  532.     while {$moreToSearch} {
  533.         set foundByContinuedSearch [expr {![catch {search -s -f $__Gcw_above_BELOW -r 1 -i 0 -m 1 -- \
  534.           $__Gcw_patt $__Gcw_nextStart} BegEnd]}]
  535.         if {!$foundByContinuedSearch} {unset BegEnd ; break}
  536.         set beg [lindex $BegEnd 0]
  537.         set end [lindex $BegEnd 1]
  538.         set Hit [getText $beg $end]
  539.         unset BegEnd
  540.         
  541.         set fullMatch [elec::acronymsAreEqual $__Gcw_prevHint $Hit]
  542.         if {$fullMatch} {
  543.         break
  544.         } else {
  545.         set foundBelow 0
  546.         }
  547.         
  548.         if {[pos::compare $end >= [maxPos]]} {
  549.         set moreToSearch 0
  550.         } else {
  551.         elec::_adjustGlobals __Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart
  552.         }
  553.     }
  554.     }
  555. }
  556.  
  557. #    --------------  -in-------------  -mod-------------   -out-----------
  558. proc elec::_adjustGlobals {__Gcw_endPrevRpl  __Gcw_above_BELOW   __Gcw_nextStart} {
  559.     
  560.     uplevel {
  561.     if {$__Gcw_above_BELOW} {
  562.         set __Gcw_nextStart $end
  563.     } else {
  564.         set __Gcw_nextStart [pos::math $beg - 1]
  565.         if {[pos::compare $__Gcw_nextStart <= [minPos]]} {
  566.         set __Gcw_above_BELOW 1
  567.         set __Gcw_nextStart $__Gcw_endPrevRpl
  568.         }
  569.     }
  570.     }
  571. }
  572.  
  573.  
  574.  
  575. #    ----------(bool)  -in- ---------------
  576. proc elec::acronymsAreEqual {hint wordCombination} {
  577.     
  578.     
  579.     set splitOnUndrS [split $wordCombination {_}]
  580.     set shoe {}
  581.     foreach part $splitOnUndrS {
  582.     if {$part == {}} continue
  583.     set part [split $part {}]
  584.     set part [lreplace $part 0 0 [string toupper [lindex $part 0]]]
  585.     set part [join $part {}]
  586.     append shoe $part
  587.     }
  588.     regsub -all \[a-z0-9\] $shoe {} shoe
  589.     return [expr {![string compare [string toupper $hint] $shoe]}]
  590. }
  591.  
  592.  
  593. ## 
  594.  # -------------------------------------------------------------------------
  595.  #     
  596.  #    "elec::acronymListExpansions" --
  597.  #    
  598.  #  Given a an acronym of the sub-words in a 'multi-word command' (the
  599.  #  'hint') and the name of a list to search, that list consisting of
  600.  #  acronyms-command pairs on separate lines that have been placed in
  601.  #  alphabetical order and starting/ending with a return, this proc
  602.  #  returns a list of all pairs that have the hint as their first
  603.  #  element or'0' if there were none.
  604.  #   
  605.  #     Based on Vince Darley's modeListCompletions
  606.  # -------------------------------------------------------------------------
  607.  ##
  608. proc elec::acronymListExpansions { hint dictName } {
  609.     global $dictName
  610.     
  611.     set reg {(\n}
  612.     append reg $hint { +[^\n]+)+}
  613.     if {[regexp $reg [set $dictName] pairs]} {
  614.     set odd 1
  615.     foreach m $pairs {
  616.         if {$odd % 2 != 0} {
  617.         incr odd
  618.         continue
  619.         } 
  620.         incr odd
  621.         append matches $m " "
  622.     }
  623.     return $matches
  624.     } else {
  625.     return 0
  626.     }
  627. }
  628.  
  629. proc elec::expandThis { cmd matches {isdbllist 0} {forcequery 0}} {
  630.     global possMatches returnedMatch listPickIfMultExpds
  631.     
  632.     set possMatches $matches
  633.     set mquery [set match [lindex $matches 0]]
  634.     if {$isdbllist} { set match [lindex [lindex $match 0] 0]}
  635.     if { [set cmdnum [llength $matches]] == 1 || $match == $cmd } {
  636.     # It's unique or already a command, so insert it 
  637.     backwardDeleteWord
  638.     elec::commandPrefix
  639.     insertText $match
  640.     return $match
  641.     } else {
  642.     set item [lindex $matches [incr cmdnum -1]]
  643.     if {$isdbllist} { set item [lindex [lindex $item 0] 0] }
  644.     
  645.     set num 1
  646.     set correspondingNum 1
  647.     set numberedChoices "\{"
  648.     set currChoiceSet ""
  649.     set setIdx 0
  650.     set multiSets 0
  651.     set pickNumOfStartIn(0) $correspondingNum
  652.     foreach m $matches {
  653.         append numberedList "\{$num $m\} "
  654.         #make up a list of choiceSets, where eadh choice set has < 79
  655.         # characters
  656.         if {[string length "$currChoiceSet$correspondingNum $m "] < 77} {
  657.         append numberedChoices "$correspondingNum $m "
  658.         append currChoiceSet   "$correspondingNum $m "
  659.         set setAndNum($num) [list $setIdx $correspondingNum]
  660.         } else {
  661.         incr setIdx
  662.         set correspondingNum 1
  663.         append numberedChoices "m…\} \{$correspondingNum $m "
  664.         set currChoiceSet      "$correspondingNum $m "
  665.         set setAndNum($num) [list $setIdx $correspondingNum]
  666.         set pickNumOfStartIn($setIdx) $num
  667.         set multiSets 1
  668.         }
  669.         incr correspondingNum
  670.         incr num
  671.     }
  672.     if {$multiSets} {
  673.         append numberedChoices "b…\}"
  674.     } else {
  675.         append numberedChoices "\}"
  676.     }
  677.     
  678.     
  679.     
  680.     if { $listPickIfMultExpds } {
  681.         beep
  682.         if {[catch { set choice [listpick -p "Pick an expansion" $numberedList]}]} {
  683.         message "Cancelled"
  684.         return 1
  685.         } else {
  686.         backwardDeleteWord
  687.         elec::commandPrefix
  688.         set choice [lindex $choice 1]
  689.         insertText $choice
  690.         return $choice
  691.         }
  692.         
  693.     } else {
  694.         set pickNum 1
  695.         set promptNum $pickNum
  696.         set currChoiceSet_idx 0
  697.         set c "\t"
  698.         backwardDeleteWord
  699.         elec::commandPrefix
  700.         insertText [lindex $matches 0]
  701.         
  702.         while {[set c] == "\t"} {
  703.         set currChoiceSet_idx [lindex $setAndNum($pickNum) 0]
  704.         set currChoiceSet     [lindex $numberedChoices $currChoiceSet_idx]
  705.         #look up what number in the currChoiceSet corresponds to the pickNum
  706.         set currNum [lindex $setAndNum($pickNum) 1]
  707.         regsub "$currNum " $currChoiceSet "=>" choices
  708.         global returnedMatch
  709.         set returnedMatch ""
  710.         
  711.         message $choices
  712.         set c [getChar]
  713.         set c [string tolower $c ]
  714.         scan $c "%c" decRep
  715.         if {$decRep == 27} {
  716.             set c "esc"
  717.         } 
  718.         switch -- $c {
  719.             "\t" {
  720.             incr pickNum
  721.             if {$pickNum > [llength $matches]} {
  722.                 set pickNum 1
  723.             } 
  724.             backwardDeleteWord
  725.             elec::commandPrefix
  726.             insertText [lindex $matches [expr {$pickNum -1}]]
  727.             #set things up so we cylce to the next choice
  728.             continue                      
  729.             }
  730.             " " -
  731.             "\\" -
  732.             "\r" {
  733.             #these keys indicate that we are satisfied with the current choice,
  734.             # just insert the key pressed
  735.             #                       alertnote "you pressed a return, \\, or space"
  736.             #                       alertnote "pickNum = $pickNum"
  737.             return [list [lindex $matches [expr {$pickNum -1}]] $c]
  738.             }
  739.             "m" {
  740.             #when there are more choices than can be diplayed on the statusline
  741.             # pressing 'm', will get the next set of choices
  742.             if {[string match "*m…" $currChoiceSet]} {
  743.                 set pickNum $pickNumOfStartIn([expr {$currChoiceSet_idx +1}])
  744.             }
  745.             if {[string match "*b…" $currChoiceSet]} {
  746.                 set pickNum 1
  747.             } 
  748.             backwardDeleteWord
  749.             elec::commandPrefix
  750.             insertText [lindex $matches [expr {$pickNum -1}]]
  751.             #set things up so we cylce to the next choice
  752.             set c "\t"
  753.             continue
  754.             }
  755.             "b" {
  756.             #when there are more choices than can be diplayed on the statusline
  757.             # pressing 'b', will get the first set of choices
  758.             set pickNum 1
  759.             set c "\t"
  760.             backwardDeleteWord
  761.             elec::commandPrefix
  762.             insertText [lindex $matches [expr {$pickNum -1}]]
  763.             #set things up so we cylce to the next choice
  764.             continue
  765.             }
  766.             "esc" {
  767.             #when you want to bypass this and get to acronymExpansion
  768.             backwardDeleteWord
  769.             insertText $cmd
  770.             return 0
  771.             }
  772.             "default" {
  773.             #see if c is, or can be converted to, a number in the range 1-9
  774.             set strPos [string first $c "asdfghjkl123456789"]
  775.             if {$strPos == -1} {
  776.                 beep
  777.                 return
  778.             }
  779.             set numberChoosen [expr {$strPos % 9}]
  780.             if {$numberChoosen > [llength $possMatches]} {
  781.                 beep
  782.                 return
  783.             } 
  784.             #alertnote "you choose number $numberChoosen"    
  785.             set returnedMatch [lindex $possMatches [expr {$pickNumOfStartIn($currChoiceSet_idx) + $numberChoosen -1}]]
  786.             
  787.             
  788.             }
  789.         }
  790.         #             catch {statusPrompt -f $choices statusLineChooser}
  791.         if {$returnedMatch != ""} {
  792.             backwardDeleteWord
  793.             elec::commandPrefix
  794.             insertText $returnedMatch
  795.             return $returnedMatch                
  796.         } 
  797.         
  798.         }
  799.         
  800.     }
  801.     
  802.     return ""
  803.     }
  804.     
  805.     
  806. }
  807.  
  808.  
  809.  
  810. proc elec::commandPrefix {} {
  811.     global mode
  812.     
  813.     switch -- $mode {
  814.     "TeX" {
  815.         set pos [getPos]
  816.         set bol [getText [lineStart $pos] $pos]
  817.         switch -glob $bol {
  818.         "*\\begin\{" -
  819.         "*\\end\{" - 
  820.         "*\\" {
  821.             return
  822.         }
  823.         "default" {
  824.             insertText "\\"
  825.         }
  826.         }
  827.     }
  828.     }
  829. }
  830.                     
  831.  
  832.  
  833.